﻿#pragma once

#include <memory>
#include "discrete_face_utils.hxx"
class DECL_FCT FacetMesh {
public:
    struct FaceMesh {
        unsigned int numIndices;
        unsigned int baseVertex;
        unsigned int baseIndex;
        FaceMesh() {
            numIndices = 0;
            baseVertex = 0;
            baseIndex = 0;
        }
    };
    struct EdgeMesh {
        unsigned int numIndices;
        unsigned int baseVertex;
        EdgeMesh() {
            numIndices = 0;
            baseVertex = 0;
        }
    };
    struct DisplayData {
        std::vector<double> faceCoords;
        std::vector<double> normalCoords;
        std::vector<double> uvCoords;
        std::vector<int> triangles;
        std::vector<double> edgeCoords;
        std::vector<double> paramCoords;
        std::vector<FacetMesh::FaceMesh> faceMesh;
        std::vector<FacetMesh::EdgeMesh> edgeMesh;
    };

    struct FaceData {
        unsigned int vertex_Nb = 0;
        unsigned int triangle_Nb = 0;
        std::vector<double> coords, normal_coords, uv_coords;
        std::vector<int> triangles;
        FaceData() = default;
    };
    struct EdgeData {
        unsigned int vertex_Nb = 0;
        std::vector<double> coords, param_coords;
        EdgeData() = default;
    };
};

struct FacetParameters {
    FacetParameters() = default;

    FacetParameters(facet_options_visualization* fo, double diag) {
        get_face_tolerance(diag, fo, surface_tolerance, normal_tolerance);
        get_edge_tolerance(diag, fo, distance_tolerance_edge, angle_tolerance_edge);
    }

    FacetParameters(facet_options_visualization fo, double diag) {
        get_face_tolerance(diag, &fo, surface_tolerance, normal_tolerance);
        get_edge_tolerance(diag, &fo, distance_tolerance_edge, angle_tolerance_edge);
    }

    bool relative = true;  // 容差是否相对于对角线长度
    double surface_tolerance;
    double normal_tolerance;
    bool edge_tolerance_relative = true;  // 边容差是否相对于面容差
    double edge_tolerance_factor = 0.5;

    double distance_tolerance_edge;
    double angle_tolerance_edge;
};

class EdgeMeshData {
public:
    EdgeMeshData() = default;
    ~EdgeMeshData() = default;

    // 预先分配空间
    explicit EdgeMeshData(EDGE* edge) : edge_(edge) {
        int num_pts = 0;
        SPAposition* pos_array = nullptr;
        double* param_array = nullptr;
        get_facet_edge_points_and_params(edge, pos_array, param_array, num_pts);
        pos_.reserve(num_pts);
        param_.reserve(num_pts);
        ENTITY_LIST face_list;
        api_get_faces(edge, face_list);
        for (FACE* f = dynamic_cast<FACE*>(face_list.first()); f != NULL; f = dynamic_cast<FACE*>(face_list.next())) {
            face_pcurve_map_[f].reserve(num_pts);
        }

        for (int i = 0; i < num_pts; i++) {
            pos_.emplace_back(pos_array[i]);
            param_.emplace_back(param_array[i]);
            for (auto& it : face_pcurve_map_) {
                it.second.push_back(it.first->geometry()->equation().param(pos_array[i]));
            }
        }

        ACIS_DELETE pos_array;
        ACIS_DELETE param_array;
    }

    const std::vector<SPAposition>& GetPos() const { return pos_; }
    const std::vector<double>& GetParam() const { return param_; }
    const std::vector<SPApar_pos>& GetFacePcurve(FACE* face) const {
        auto it = face_pcurve_map_.find(face);
        if (it != face_pcurve_map_.end()) {
            return it->second;
        }
        throw std::runtime_error("FACE not found");
    }

private:
    EDGE* edge_ = nullptr;
    std::vector<SPAposition> pos_;
    std::vector<double> param_;
    std::unordered_map<FACE*, std::vector<SPApar_pos>> face_pcurve_map_;

    // 为了允许 FacetContext 访问私有成员
    friend class FacetContext;
};

class FacetContext {
public:
    FacetContext() = default;
    FacetContext(ENTITY* entity) : entity_(entity) {
        SPAposition min_pt, max_pt;
        api_get_entity_box(entity_, min_pt, max_pt);
        double diag = (max_pt - min_pt).len();

        facet_options_visualization* fo = ACIS_NEW facet_options_visualization();
        fo->set_edge_quality(edge_quality_level::better);
        fo->set_face_quality(face_quality_level::medium_coarse);

        facet_parameters = FacetParameters(fo, diag);

        ACIS_DELETE fo;
    }
    FacetContext(ENTITY* entity, facet_options_visualization* fo) : entity_(entity) {
        SPAposition min_pt, max_pt;
        api_get_entity_box(entity_, min_pt, max_pt);
        double diag = (max_pt - min_pt).len();
        facet_parameters = FacetParameters(fo, diag);
    }
    ~FacetContext() {}

    // 根据 EDGE* 获取 pos
    const std::vector<SPAposition>& GetEdgePos(EDGE* edge) const {
        auto it = edge_data_map_.find(edge);
        if (it != edge_data_map_.end()) {
            return it->second.GetPos();
        }
        throw std::runtime_error("EDGE not found");
    }

    // 根据 EDGE* 获取 param
    const std::vector<double>& GetEdgeParam(EDGE* edge) const {
        auto it = edge_data_map_.find(edge);
        if (it != edge_data_map_.end()) {
            return it->second.GetParam();
        }
        throw std::runtime_error("EDGE not found");
    }

    // 根据 FACE* 和 EDGE* 获取 SPApar_pos
    const std::vector<SPApar_pos>& GetEdgeFacePcurve(FACE* face, EDGE* edge) const {
        auto it = edge_data_map_.find(edge);
        if (it != edge_data_map_.end()) {
            return it->second.GetFacePcurve(face);
        }
        throw std::runtime_error("EDGE not found");
    }

    const FacetParameters& GetParameters() const { return facet_parameters; }

    // 添加 EDGE 和 EdgeMeshData 的方法
    void AddEdgeData(EDGE* edge, const EdgeMeshData& data) { edge_data_map_[edge] = data; }

    outcome FacetEdge(EDGE*);
    outcome FacetFace(FACE*);
    outcome Facet();

private:
    ENTITY* entity_;
    std::unordered_map<EDGE*, EdgeMeshData> edge_data_map_;
    FacetParameters facet_parameters;
};


/**
 * 离散化一个面，根据面的类型选择不同的函数调用
 * @param nt normal_tolerance，法向容差
 * @param st surface_tolerance，表面容差.
 */
outcome facet_face(FACE* f, double st = 0, double nt = 0);

outcome FacetFace(FACE* f, std::unique_ptr<FacetContext>& facet_context, double st = 0, double nt = 0);
/**
 * 通用的算法实现.
 */
outcome facet_face_general(FACE* f, double nt, double st);

class FaceFaceterDispacher {
public:
    template <typename FaceFaceterVersion> static void dispatch(FACE* face, FacetParameters* config) {
        switch (face->geometry()->equation().type()) {
        case plane_type:  // <pladef.hxx> plane_type
            // printf("PLANE\n");
            FaceFaceterVersion::PlaneFaceter::facet(face, config);
            // Facet<PlaneFaceter>(face, config);
            break;
        default:
            break;
        }
    }
};

